/***************************************************************************
 *   Copyright (C) 2004 by cyril dupuit                                    *
 *   cyrildupuit@hotmail.com                                               *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/

//*****************************************************************************
// Nom du module : Paging.h
// Description : Gestion de la pagination
//*****************************************************************************
 
// Historique :
// 28/10/04 : Creation du module V1.0  

#include "Kernel/Types.h"

#ifndef PAGING_HEADER
#define PAGING_HEADER

//*****************************************************************************
// Definition des equivalences :
//*****************************************************************************

#define VM_MAP_PROT_NONE  0
#define VM_MAP_PROT_READ  (1<<0)
#define VM_MAP_PROT_WRITE (1<<1)
#define VM_MAP_PROT_EXEC  (1<<2) /* Not supported on IA32 */

#define VM_MAP_ATOMIC     (1<<31)

#define PAGING_BASE_USER_ADDRESS (0x40000000) /* 1GB (must be 4MB-aligned) */
#define PAGING_TOP_USER_ADDRESS  (0xFFFFFFFF) /* 4GB - 1B */
#define PAGING_USER_SPACE_SIZE   (0xc0000000) /* 3GB */

#define MIRROR_VADDR 0x3fc00000 /* 1GB - 4MB */
#define MIRROR_SIZE  (1 << 22)  /* 1 PD = 1024 Page Tables = 4MB */

//*****************************************************************************
// Structure d'une entree de repertoire de page
//*****************************************************************************
struct Pde {
	unsigned long present        :1; /* 1=PT mapped */
	unsigned long write          :1; /* 0=read-only, 1=read/write */
	unsigned long user           :1; /* 0=supervisor, 1=user */
	unsigned long write_through  :1; /* 0=write-back, 1=write-through */
	unsigned long cache_disabled :1; /* 1=cache disabled */
	unsigned long accessed       :1; /* 1=read/write access since last clear */
	unsigned long zero           :1; /* Intel reserved */
	unsigned long page_size      :1; /* 0=4kB, 1=4MB or 2MB (depending on PAE) */
	unsigned long global_page    :1; /* Ignored (Intel reserved) */
	unsigned long custom         :3; /* Do what you want with them */
	unsigned long pt_paddr       :20;
} __attribute__ ((packed));

/** Intermediate type to speed up PDE copy */
typedef union {
	struct Pde Pde;
	unsigned long ui32;
} PdeVal_t;

//*****************************************************************************
// Structure d'une entree de table de pages
//*****************************************************************************
struct Pte {
	unsigned long present        :1; /* 1=PT mapped */
	unsigned long write          :1; /* 0=read-only, 1=read/write */
	unsigned long user           :1; /* 0=supervisor, 1=user */
	unsigned long write_through  :1; /* 0=write-back, 1=write-through */
	unsigned long cache_disabled :1; /* 1=cache disabled */
	unsigned long accessed       :1; /* 1=read/write access since last clear */
	unsigned long dirty          :1; /* 1=write access since last clear */
	unsigned long zero           :1; /* Intel reserved */
	unsigned long global_page    :1; /* 1=No TLB invalidation upon cr3 switch (when PG set in cr4) */
	unsigned long custom         :3; /* Do what you want with them */
	unsigned long paddr          :20;
} __attribute__ ((packed));

/** Intermediate type to speed up PTE copy */
typedef union {
	struct Pte pte;
	unsigned long ui32;
} PteVal_t;

//*****************************************************************************
// Structure du registre CR3 : Registre de base du repertoire de pages
//*****************************************************************************
struct Pdbr {
	unsigned long zero1          :3; /* Intel reserved */
	unsigned long write_through  :1; /* 0=write-back, 1=write-through */
	unsigned long cache_disabled :1; /* 1=cache disabled */
	unsigned long zero2          :7; /* Intel reserved */
	unsigned long pd_paddr       :20;
} __attribute__ ((packed));

//*****************************************************************************
// Macro de gestion de la MMU : Invalide l'entree de la TLB en fonction de son
// adresse virtuelle
//*****************************************************************************
#define invlpg(Vaddr) \
  do { \
       __asm__ __volatile__("invlpg %0"::"m"(*((unsigned *)(Vaddr)))); \
  } while(0)

//*****************************************************************************
// Macro de gestion de la MMU : Vider toute la TLB
//*****************************************************************************
#define flush_tlb() \
  do { \
        unsigned long tmpreg; \
        asm volatile("movl %%cr3,%0\n\tmovl %0,%%cr3" :"=r" \
                     (tmpreg) : :"memory"); \
  } while (0)

//*****************************************************************************
// Convertir une adresse virtuelle en index de repertoire de pages
//*****************************************************************************
#define VirtToPdIndex(Vaddr) (((unsigned long)(Vaddr)) >> 22)

//*****************************************************************************
// Convertir une adresse virtuelle en index de table de pages
//*****************************************************************************
#define VirtToPtIndex(Vaddr) ((((unsigned long)(Vaddr)) >> 12) & 0x3ff)

//*****************************************************************************
// Convertir une adresse virtuelle en offset de page
//*****************************************************************************
#define VirtToPageOffset(Vaddr) (((unsigned long)(Vaddr)) & PAGE_MASK)

//*****************************************************************************
// But de la fonction : Mettre en place le mirroring et initialiser la
// pagination.
// Entree : Aucune
// Parametre retourne : ERROR si la table des pages est invalide, TRUE sinon
//*****************************************************************************
Status_t PagingInit(void);

//*****************************************************************************
// But de la fonction : Ajouter une traduction adresse lineaire -> adresse
// physique
// Entrees : 
//	Paddr : Adresse de la page physique
//	Vaddr : Adresse de la page virtuelle
//	IsUser : Booleen representant le type de page (superviseur ou 
//			utilisateur)
//	Flags : Drapeau associe a la page
// Parametre retourne : ERROR si la table des pages est invalide ou si
// l'adresse virtuelle est invalide, TRUE sinon
//*****************************************************************************
Status_t PagingMap(PhysAddr_t Paddr, VirtAddr_t Vaddr, Status_t IsUser, MemFlags_t Flags);

//*****************************************************************************
// But de la fonction : Retirer le mappage d'une adresse virtuelle
// Entree :
//	Vaddr : Adresse de la page virtuelle
// Parametre retourne : ERROR si le repertoire de page est invalide ou si la
// table des pages est invalide ou encore si l'adresse virtuelle es tinvalide,
// TRUE sinon
//*****************************************************************************
Status_t PagingUnmap(VirtAddr_t Vaddr);

//*****************************************************************************
// But de la fonction : Obtenire les drapeaux de fonctionnement de la page
// virtuelle vaddr
// Entree : 
//	Vaddr : Adresse virtuelle
// Parametre retourne : Drapeau de l'adresse virtuelle
//*****************************************************************************
MemFlags_t PagingGetFlag(VirtAddr_t Vaddr);

//*****************************************************************************
// But de la fonction : Obtenir l'adresse physique d'une adresse virtuelle
// Entree :
//	Vaddr : Adresse virtuelle
// Parametre retourne : Adresse physique
//*****************************************************************************
PhysAddr_t PagingGetPhysAddr(VirtAddr_t Vaddr);

//*****************************************************************************
// Regarder si l'adresse virtuelle est mappee
//*****************************************************************************
#define PagingCheckPresent(Vaddr) (PagingGetPhysAddr(Vaddr) != NULL)

//*****************************************************************************
#endif
